﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Threading;

namespace exsportance.Silverlight.Common.Helper
{
    public class UISynchronizationContext
    {
        #region member
        private Dispatcher _dispatcher;
        private DispatcherSynchronizationContext _context;
        private static readonly UISynchronizationContext _instance = new UISynchronizationContext();
        #endregion

        #region properties
        public static UISynchronizationContext Instance
        {
            get { return _instance; }
        }

        public bool InvokeRequired
        {
            get
            {
                return !_dispatcher.CheckAccess();
            }
        }

        public bool IsValid
        {
            get { return _dispatcher != null; }
        }
        #endregion

        #region public methods
        public void Initialize()
        {
            if (Application.Current.RootVisual != null)
            {
                _dispatcher = Application.Current.RootVisual.Dispatcher;
                _context = new DispatcherSynchronizationContext(_dispatcher);
            }
            else
            {
                throw new Exception("Application.Instance.RootVisual should not be null. Use Initialize(Dispatcher) or leave initialization until after RootVisual is instantiated.");
            }
        }

        public void Initialize(Dispatcher dispatcher)
        {
            if (dispatcher == null)
                throw new ArgumentNullException("calldispatcherback");

            _dispatcher = dispatcher;
            _context = new DispatcherSynchronizationContext(dispatcher);
        }


        public void InvokeAsynchronously(SendOrPostCallback callback, object state)
        {
            if (callback == null)
                throw new ArgumentNullException("callback");

            if (_context != null)
                _context.Post(callback, state);
        }

        public void InvokeAsynchronously(Action action)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            if (_dispatcher != null)
            {
                if (_dispatcher.CheckAccess())
                {
                    action();
                }
                else
                {
                    _dispatcher.BeginInvoke(action);
                }
            }
        }

        public void InvokeSynchronously(SendOrPostCallback callback, object state)
        {
            if (callback == null)
                throw new ArgumentNullException("callback");

            if (_context != null)
                _context.Send(callback, state);
        }

        public void InvokeSynchronously(Action action)
        {
            if (action == null)
                throw new ArgumentNullException("action");

            if (_dispatcher != null && _context != null)
            {
                if (_dispatcher.CheckAccess())
                {
                    action();
                }
                else
                {
                    _context.Send(delegate { action(); }, null);
                }
            }
        }
        #endregion
    }
}
